package com.train.web.handler;

import cn.hutool.core.util.StrUtil;
import com.train.common.enums.impl.SysExceptionEnums;
import com.train.common.exception.GlobalException;
import com.train.common.resp.CommonResp;
import com.train.common.status.HttpStatus;
import com.train.common.utils.exception.ExceptionUtils;
import io.seata.core.context.RootContext;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.Optional;

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 请求参数校验异常
     * @param e
     * @param request
     * @return
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public CommonResp handleMethodArgumentNotValidException(MethodArgumentNotValidException e, HttpServletRequest request) {
        log.error("请求地址'{}', 异常原因'{}'", request.getRequestURI(), ExceptionUtils.getExpMsg(e));
        FieldError fieldError = e.getBindingResult().getFieldError();
        assert fieldError != null;
        return CommonResp.error(HttpStatus.BAD_REQUEST, fieldError.getDefaultMessage());
    }

    /**
     * jsr303验证异常
     * @param e
     * @param request
     * @return
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public CommonResp handleMethodArgumentNotValidException(ConstraintViolationException e, HttpServletRequest request) {
        log.error("请求地址'{}', 异常原因'{}'", request.getRequestURI(), ExceptionUtils.getExpMsg(e));
        Optional<ConstraintViolation<?>> first = e.getConstraintViolations().stream().findFirst();
        assert first.isPresent(); // 断言，避免告警
        return CommonResp.error(HttpStatus.BAD_REQUEST, first.get().getMessage());
    }

    /**
     * 请求方式不支持异常
     * @param e
     * @param request
     * @return
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public CommonResp handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e,
                                                            HttpServletRequest request) {
        SysExceptionEnums expMethodNotSupport = SysExceptionEnums.EXP_METHOD_NOT_SUPPORT;
        log.error("请求地址'{}',不支持'{}'请求", request.getRequestURI(), e.getMethod());
        return CommonResp.error(expMethodNotSupport.getCode(), expMethodNotSupport + "'" + request.getMethod() + "'");
    }

    /**
     * 自定义全局业务/系统异常
     * @param e
     * @param request
     * @return
     */
    @ExceptionHandler(value = GlobalException.class)
    public CommonResp handleGlobalException(GlobalException e, HttpServletRequest request) {
        log.error("请求地址'{}', 异常原因'{}'", request.getRequestURI(), ExceptionUtils.getExpMsg(e));
        return CommonResp.error(e.getCode(), e.getMessage());
    }

    /**
     * 兜底异常
     * @param e
     * @param request
     * @return
     */
    @ExceptionHandler(value = Exception.class)
    public CommonResp handleDefaultException(Exception e, HttpServletRequest request) throws Exception {
        if (StrUtil.isNotEmpty(RootContext.getXID())) {
            throw e; //抛出全局事物异常
        }
        SysExceptionEnums exceptionEnums = SysExceptionEnums.EXP_SERVER;//默认异常返回信息
        String message = exceptionEnums.getMessage();
        log.error("{}", message);
        log.error("请求地址'{}', 异常原因'{}'", request.getRequestURI(), ExceptionUtils.getExpMsg(e));
        return CommonResp.error(exceptionEnums.getCode(), message);
    }
}
